package com.hks360.car_treasure.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;


import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Handler;
import android.text.format.DateFormat;
import android.text.format.Time;
import android.util.Log;
import android.util.Xml.Encoding;
import android.widget.Toast;

import com.hks360.car_treasure.common.Constant;
import com.hks360.car_treasure.util.LogUtil;
import com.hks360.library.util.CommonUtil;
import com.hks360.library.util.StringUtil;
import com.hks360.library.widget.ILoadingDialog;

/**
 * 登录后数据通讯
 *
 * @author lxy
 */
public class CommunicationManager {
    private String TAG = CommunicationManager.class.getName();
    private Context mContext;

    private String ADDRESS = "tbox.goldhonor.com";

    public void setADDRESS(String ADDRESS) {
        this.ADDRESS = ADDRESS;
    }

    public void setPOT(int POT) {
        this.POT = POT;
    }

    private int POT = 5050;
    private static final String ENCODE = "UTF-8";
    private Socket mSocket = null;
    SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");

    private boolean isExist = false;
    private boolean isShow = true;
    public boolean isFalse = false;
    /*--------------------控制命令--------------------------------*/
    /**
     * 点火
     */
    public static final int SEND_CONTROLL_CMD_FIRE_ON = 0x0901;
    /**
     * 熄火
     */
    public static final int SEND_CONTROLL_CMD_FIRE_OFF = 0x0902;
    /**
     * 开中控门锁
     */
    public static final int SEND_CONTROLL_CMD_DOOR_LOCK_OFF = 0x0903;
    /**
     * 关中控门锁
     */
    public static final int SEND_CONTROLL_CMD_DOOR_LOCK_ON = 0x0904;
    /**
     * 开尾门
     */
    public static final int SEND_CONTROLL_CMD_BACK_DOOR_ON = 0x0905;
    /**
     * 关尾门
     */
    public static final int SEND_CONTROLL_CMD_BACK_DOOR_OFF = 0x0906;
    /**
     * 降主驾驶窗
     */
    public static final int SEND_CONTROLL_CMD_DRIVE_WINDOW_DOWN = 0x0907;
    /**
     * 升主驾驶窗
     */
    public static final int SEND_CONTROLL_CMD_DRIVE_WINDOW_UP = 0x0908;
    /**
     * 降全部窗
     */
    public static final int SEND_CONTROLL_CMD_WINDOWS_DOWN = 0x0909;
    /**
     * 升全部窗
     */
    public static final int SEND_CONTROLL_CMD_WINDOWS_UP = 0x090A;
    /**
     * 防盗锁定汽车
     */
    public static final int SEND_CONTROLL_CMD_LOCK_CAR = 0x090B;
    /**
     * 解除防盗锁定
     */
    public static final int SEND_CONTROLL_CMD_UNLOCK_CAR = 0x090C;
    /**
     * 寻车
     */
    public static final int SEND_CONTROLL_CMD_SEARCHING_CAR = 0x090D;
    /**
     * 强制休眠
     */
    public static final int SEND_CONTROLL_CMD_FORCE_SLEEP_CAR = 0x090E;

    /**
     * 冷风低
     */
    public static final int SEND_CONTROLL_CMD_COOL_WIND_L = 0x0101;
    /**
     * 冷风中
     */
    public static final int SEND_CONTROLL_CMD_COOL_WIND_M = 0x0102;
    /**
     * 冷风高
     */
    public static final int SEND_CONTROLL_CMD_COOL_WIND_H = 0x0103;
    /**
     * 暖风低
     */
    public static final int SEND_CONTROLL_CMD_WARM_WIND_L = 0x0104;
    /**
     * 暖风中
     */
    public static final int SEND_CONTROLL_CMD_WARM_WIND_M = 0x0105;
    /**
     * 暖风高
     */
    public static final int SEND_CONTROLL_CMD_WARM_WIND_H = 0x0106;
    /**
     * 空调关闭
     */
    public static final int SEND_CONTROLL_CMD_AIR_OFF = 0x0107;
    /**
     * 自动空调开启并设置温度
     */
    public static final int SEND_CONTROLL_CMD_AUTO_AIR_TEMP = 0x0108;
    /**
     * 前除霜开
     */
    public static final int SEND_CONTROLL_CMD_FRONT_DEFROSTING_ON = 0x010B;
    /**
     * 前除霜关
     */
    public static final int SEND_CONTROLL_CMD_FRONT_DEFROSTING_OFF = 0x010C;
    /**
     * 后除霜开
     */
    public static final int SEND_CONTROLL_CMD_REAR_DEFROSTING_ON = 0x010D;
    /**
     * 后除霜关
     */
    public static final int SEND_CONTROLL_CMD_REAR_DEFROSTING_OFF = 0x010E;
    /**
     * 座椅加热开
     */
    public static final int SEND_CONTROLL_CMD_SEAT_HEATING_ON = 0x010F;
    /**
     * 座椅加热关
     */
    public static final int SEND_CONTROLL_CMD_SEAT_HEATING_OFF = 0x0110;

    /**
     * 强制升级TBOX
     */
    public static final int SEND_CONTROLL_CMD_FORCE_UPDATE = 0x0FFF;

    private OnRecvCommunicationListener mRecvCommunicationListener;

    public void setOnRecvCommunicationListener(
            OnRecvCommunicationListener mRecvCommunicationListener) {
        this.mRecvCommunicationListener = mRecvCommunicationListener;
    }

    public static interface OnRecvCommunicationListener {

        void onRecv_B001(int answerID, byte[] message);

        void onRecv_B601(String description);

        void onRecv_A602(List<String> llr);

        void onRecv_B500(byte[] message);

        void onRecv_B208(List<PhoneBandDevice> itemsDevices);

        void onRecv_CarStatus(byte[] carStatusBytes);

        void onRecv_Gps(byte[] gpsBytes);

        void onConnectBreak();

        void onRecv_B208Error();

    }

    public CommunicationManager(Context context) {
        mContext = context;
        isExist = false;
    }

    public void onStart() {
        isShow = true;
    }

    public void onStop() {
        isShow = false;
    }

    public void onDestroy() {
        if (mHeartBeat != null) {
            mHeartBeat.interrupt();
            mHeartBeat = null;
        }
        isExist = true;
    }

    private String userName;
    private String phoneNum;
    private String loadIMEI = "";
    private String code;
    private String password;
    private String passwordMD5;
    // 用户数据库ID
    private int userID = -1;

    // private int newVersion = -1;

    public String getUserName() {
        return userName;
    }

    public String getLoadIMEI() {
        return loadIMEI;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public String getPassword() {
        return password;
    }

    public String getCode() {
        return code;
    }

    /**
     * 获取验证码
     */
    public void getCaptcha(String phoneNum) {
        this.phoneNum = phoneNum;
        if (mConnectNet == null) {
            mConnectNet = new ConnectNet(ConnectNet.CONNECT_MODE_GETYZM);
            mConnectNet.start();
        } else {
            sendControl(getBYZM());
        }
    }

    /**
     * 注册
     *
     * @param userName 用户名
     * @param phoneNum 电话
     * @param code     验证码
     * @param password 密码
     */
    public void register(String userName, String phoneNum, String code,
                         String password) {
        this.userName = userName;
        this.phoneNum = phoneNum;
        this.code = code;
        this.password = password;
        try {
            passwordMD5 = getMD5(password);
        } catch (NoSuchAlgorithmException e) {
            this.passwordMD5 = "";
            e.printStackTrace();
        }
        if (mConnectNet == null) {
            mConnectNet = new ConnectNet(ConnectNet.CONNECT_MODE_REGISTER);
            mConnectNet.start();
        } else {
            sendControl(getBRegister(false));
        }
    }

    /**
     * 登录
     *
     * @param loadIMEI 当前使用的TBoxIMEI号（必须是以前已经绑定的）
     * @param phoneNum 电话
     * @param password 密码
     */
    public void loading(String loadIMEI, String phoneNum, String password) {
        this.loadIMEI = loadIMEI;
        this.phoneNum = phoneNum;
        this.password = password;
//		try {
//			passwordMD5 = getMD5(password);
//		} catch (NoSuchAlgorithmException e) {
//			this.passwordMD5 = "";
//			e.printStackTrace();
//		}
        if (mConnectNet == null) {
            mConnectNet = new ConnectNet(ConnectNet.CONNECT_MODE_LOGIN);
            mConnectNet.start();
        } else {
            sendControl(getBLoading());
        }
    }

    public void resetPassword(String password) {
        this.password = password;
        try {
            passwordMD5 = getMD5(password);
        } catch (NoSuchAlgorithmException e) {
            this.passwordMD5 = "";
            e.printStackTrace();
        }
        sendControl(getBRegister(true));
    }

    public Socket getmSocket() {
        return mSocket;
    }

    /**
     * 注销登录
     */
    public void unLoading() {
        if (mConnectNet != null) {
            mConnectNet.interrupt();
            mConnectNet = null;
        }
        if (mHeartBeat != null) {
            mHeartBeat.interrupt();
            mHeartBeat = null;
        }
    }

    public void getDeviceList() {
        sendControl(getBBand("", "", "", (char) 0));
    }

    public void bandDevice(String imei, String plate, String frame) {
        sendControl(getBBand(imei, plate, frame, (char) 0));
    }

    public void enableDevice(String imei, String plate, String frame) {
        sendControl(getBBand(imei, plate, frame, (char) 1));
    }

    public void delDevice(String imei, String plate, String frame) {
        sendControl(getBBand(imei, plate, frame, (char) 2));
    }

    private String imei = "";

    public String getImei() {
        return imei;
    }

    public void getCarInfo(String imei) {
        this.imei = imei;
        sendControl(getBCarInfo(imei));
    }

    public void getEfence() {
        byte[] info = null;
        byte type = 0;
        try {
            info = pkgData(0xA601, type);
        } catch (Exception e) {
            e.printStackTrace();
        }
        sendControl(info);
    }

    public void setEfence(String longtitude, String latitude, String radius) {
        String str = longtitude + (char) 0 + latitude + (char) 0 + radius + (char) 0;
        byte[] info;
        byte[] info2 = null;
        try {
            info = str.getBytes(ENCODE);
            byte[] info1 = new byte[info.length + 2];
            info1[0] = 0;
            info1[1] = 0;
            for (int i = 2; i < info1.length; i++) {
                info1[i] = info[i - 2];
            }
            info2 = pkgData(0xA602, info1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        sendControl(info2);
    }

    /**
     * 发送命令
     *
     * @param cmdID
     */
    public void sendCtrlCar(int cmdID) {
        sendControl(getBCarContr(cmdID));
    }


    private ConnectNet mConnectNet;

    private class ConnectNet extends Thread {
        // 注册链接
        public static final int CONNECT_MODE_REGISTER = 0;
        // 登录连接
        public static final int CONNECT_MODE_LOGIN = 1;
        // 获取验证码
        public static final int CONNECT_MODE_GETYZM = 2;
        private int connectMode;

        public ConnectNet(int connectMode) {
            this.connectMode = connectMode;
        }

        @Override
        public void run() {
            while (mConnectNet != null && !isExist) {
                try {
                    mSocket = new Socket(ADDRESS, POT);
                    isFalse = false;
                    Log.v(TAG, "服务器连接成功");

                    OutputStream outputStream = mSocket.getOutputStream();
                    InputStream inputStream = mSocket.getInputStream();
                    // 消息体
                    byte[] buffer = null;
                    if (connectMode == CONNECT_MODE_REGISTER) {
                        buffer = getBRegister(false);
                    } else if (connectMode == CONNECT_MODE_LOGIN) {
                        buffer = getBLoading();
                    } else if (connectMode == CONNECT_MODE_GETYZM) {
                        buffer = getBYZM();
                    }
                    // 发送注册或登录
                    printfByte("i", "send", buffer);
                    outputStream.write(buffer);
                    // 死等接收
                    while (!isExist && mSocket.isConnected()) {
                        if (mConnectNet == null)
                            break;
                        byte[] databuf = new byte[1024];
                        int readbyte = inputStream.read(databuf);
                        Log.v(TAG, "step1  readbyte: " + readbyte);
                        if (readbyte > 0) {
                            byte[] msgbuf = new byte[readbyte];
                            System.arraycopy(databuf, 0, msgbuf, 0, readbyte);
                            printfByte("d", "recv cmd", msgbuf);
                            // 找头 消息体为空 命令19个byte
                            for (int i = 0; i < msgbuf.length - 19; i++) {
                                if (msgbuf[i] == (byte) 0x9e) {// 头
                                    // 找尾
                                    int length = getCmdLength(msgbuf[i + 3],
                                            msgbuf[i + 4]);
                                    if (msgbuf.length > length + 14
                                            && msgbuf[length + 14] == (byte) 0x9e) {// 尾
                                        byte[] cmdData = new byte[length + 15];
                                        try {
                                            System.arraycopy(msgbuf, i, cmdData, 0,
                                                    cmdData.length);
                                        } catch (Exception e) {

                                        }
                                        msgParser(cmdData);
                                    }
                                }
                            }
                        } else {
                            Log.v(TAG,
                                    "step 3  connected "
                                            + mSocket.isConnected()
                                            + " closed: " + mSocket.isClosed());
                            connectMode = CONNECT_MODE_LOGIN;
//							try {
//								Thread.sleep(1000);
//							} catch (InterruptedException e) {
//								e.printStackTrace();
//							}
                            break;
                        }
                    }
                } catch (UnknownHostException e) {
                    try {
                        Thread.sleep(60000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    mHandler.sendEmptyMessage(10);
                    e.printStackTrace();
                } catch (IOException e) {
                    try {
                        Thread.sleep(60000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    mHandler.sendEmptyMessage(10);
                    e.printStackTrace();
                }
                mHandler.sendEmptyMessage(MSG_CONNT_BREAK);
                try {
                    if (mSocket != null)
                        mSocket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                mSocket = null;
                Log.v(TAG, "step 4  mSocket = null ");
//				try {
//					Thread.sleep(2000);
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
                Log.v(TAG, "step 5  isExit " + isExist);
            }
            super.run();
        }
    }



    /**
     * 解析接收命令
     *
     * @param message
     */
    private void msgParser(byte[] message) {
        List<String> llr = new ArrayList<>();
        // 反转义
        message = reEscapeCmd(message);
        // 校验
        int jy = getCheckValue(message);
        if (jy != message[message.length - 2]) {
            printfByte("e", "校验错误命令", message);
            return;
        }
        int cmdId = (message[1] & 0xff) * 0x100 + (message[2] & 0xff);
        Log.v(TAG, "cmdId " + String.format("%04X", cmdId));
        switch (cmdId) {
            case 0xB001:// 通用应答
                // 应答ID
                int answerID = (message[15] & 0xff) * 0x100 + (message[16] & 0xff);
                Log.v(TAG, "answerID: " + String.format("%04X", answerID));
                if (mRecvCommunicationListener != null)
                    mRecvCommunicationListener.onRecv_B001(answerID, message);
                // 结果描述
                String describeStr = CommunicationManager.getCmdString(message, 18);
                Log.v(TAG, "" + describeStr);
                switch (answerID) {
                    case 0xA105:// 心跳应答
                        if (message[17] != 0)
                            heartBeatTime = message[17];
                        break;
                    case 0xA103:
                        if (message[17] == 1) {
                            int userIdIndex = -1;
                            for (int i = 18; i < message.length; i++) {
                                if (message[i] == 0x0) {
                                    userIdIndex = i + 1;
                                    break;
                                }
                            }
                            userID = G_WORD(message, userIdIndex);
                            updateDeviceItems(message, userIdIndex + 2);
                        } else {
                            userID = -1;
                        }
                        break;
                    case 0xA601://电子围栏
                        if (mRecvCommunicationListener != null)
                            mRecvCommunicationListener.onRecv_A602(llr(message, 16));
                        break;
                }
                break;
            case 0xB203:// 车辆状态信息应答
                int type = G_BIT(message, 3, 6, 2);
                byte[] carStatusBytes = null;
                byte[] gpsBytes = null;
                // byte[] extrasInfoBytes;
                if (type == 0) {// 车辆状态+位置信息
                    carStatusBytes = new byte[16];
                    gpsBytes = new byte[27];
                    System.arraycopy(message, 13, carStatusBytes, 0,
                            carStatusBytes.length);
                    System.arraycopy(message, 29, gpsBytes, 0, gpsBytes.length);
                } else if (type == 1) {// 车辆状态+位置信息+附加数据

                } else if (type == 2) {// 附加数据

                } else if (type == 3) {// 位置信息

                }
                // parserCarStatus(carStatusBytes);
                // parserGps(gpsBytes);
                if (mRecvCommunicationListener != null)
                    mRecvCommunicationListener.onRecv_CarStatus(carStatusBytes);
                if (mRecvCommunicationListener != null)
                    mRecvCommunicationListener.onRecv_Gps(gpsBytes);
                break;
            case 0xB500:// 车辆控制应答
                if (mRecvCommunicationListener != null)
                    mRecvCommunicationListener.onRecv_B500(message);
                break;
            case 0xB601://电子围栏警报
                if (mRecvCommunicationListener != null)
                    mRecvCommunicationListener.onRecv_B601(CommunicationManager.getCmdString(message, 14));
                break;
            case 0xB208:// 已绑定车辆列表应答
                updateDeviceItems(message, 15);
                // itemsDevices.clear();
                // for (int i = 17; i < message.length - 2;) {
                // // imei
                // String imei = getCmdString(message, i);
                // int imeiLength = getCmdStringLength(message, i) + 1;
                // i += imeiLength;
                // // 车牌号
                // String plateNumber = getCmdString(message, i);
                // int plateLength = getCmdStringLength(message, i) + 1;
                // i += plateLength;
                // // 车架号
                // String frameNumber = getCmdString(message, i);
                // int frameLength = getCmdStringLength(message, i) + 1;
                // i += frameLength;
                // // 激活标识
                // int flag = G_BYTE(message, i);
                // i += 2;
                // boolean isActivity = false;
                // if (flag == 1)
                // isActivity = true;
                // Log.v(TAG, " imei: " + imei + " 车牌号:" + plateNumber + "  车架号: "
                // + frameNumber + "  激活: " + isActivity);
                // PhoneBandDevice device = new PhoneBandDevice(imei, plateNumber,
                // frameNumber, isActivity);
                // itemsDevices.add(device);
                // }
                // if (mRecvCommunicationListener != null)
                // mRecvCommunicationListener.onRecv_B208(itemsDevices);
                break;
        }
    }

    private List<String> llr(byte[] message, int startIndex) {
        List<String> llr = new ArrayList<>();
        String Latitude = "1";
        String Longtide = "1";
        String radius = "1";
        int i = startIndex + 3;
        // imei
        Latitude = getCmdString(message, i);
        int imeiLength = getCmdStringLength(message, i) + 1;
        i += imeiLength;
        // 车牌号
        Longtide = getCmdString(message, i);
        int plateLength = getCmdStringLength(message, i) + 1;
        i += plateLength;
        // 车架号
        radius = getCmdString(message, i);
        int frameLength = getCmdStringLength(message, i) + 1;
        i += frameLength;
        llr.add(Latitude);
        llr.add(Longtide);
        llr.add(radius);
        return llr;


    }

    private final int MSG_CONNT_BREAK = 0;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_CONNT_BREAK:
                    if (mRecvCommunicationListener != null) {
                        mRecvCommunicationListener.onConnectBreak();
                    }
                    break;
                case 10:
                    CommonUtil.showToast(mContext, "网络错误，连接失败");
                    isFalse = true;
                    break;
            }
        }

        ;
    };

    private List<PhoneBandDevice> itemsDevices = new ArrayList<PhoneBandDevice>();

    /**
     * 心跳间隔 单位秒
     */
    private byte heartBeatTime = (byte) 0x3C;
    private HeartBeat mHeartBeat = null;

    private class HeartBeat extends Thread {
        @Override
        public void run() {
            while (mHeartBeat != null && !isExist) {
                byte[] heats = new byte[1];
                heats[0] = heartBeatTime;
                byte[] heat = pkgData(0xa105, heats);
                sendControl(heat);
                try {
                    Thread.sleep(heartBeatTime * 1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            super.run();
        }
    }

    public void startHeartBeat() {
        if (mHeartBeat == null) {
            mHeartBeat = new HeartBeat();
            mHeartBeat.start();
        }
    }

    // 发送命令函数
    private Object m_Locker = new Object();

    private void sendControl(byte[] b) {
        synchronized (m_Locker) {
            printfByte("i", "send", b);
            OutputStream out;
            try {
                if (mSocket != null && mSocket.isConnected()) {
                    out = mSocket.getOutputStream();
                    out.write(b);
                    out.flush();
                }
//				Thread.sleep(200);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void updateDeviceItems(byte[] message, int startIndex) {
        itemsDevices.clear();
        int size = G_WORD(message, startIndex);
        for (int i = startIndex + 2; i < message.length - 2; ) {
            // imei
            String imei = getCmdString(message, i);
            int imeiLength = getCmdStringLength(message, i) + 1;
            i += imeiLength;
            // 车牌号
            String plateNumber = getCmdString(message, i);
            int plateLength = getCmdStringLength(message, i) + 1;
            i += plateLength;
            // 车架号
            String frameNumber = getCmdString(message, i);
            int frameLength = getCmdStringLength(message, i) + 1;
            i += frameLength;
            // 激活标识
            int flag = G_BYTE(message, i);
            i += 2;
            boolean isActivity = false;
            if (flag == 1)
                isActivity = true;
            Log.v(TAG, " imei: " + imei + " 车牌号:" + plateNumber + "  车架号: "
                    + frameNumber + "  激活: " + isActivity);
            PhoneBandDevice device = new PhoneBandDevice(imei, plateNumber,
                    frameNumber, isActivity);
            itemsDevices.add(device);
        }
        if (size == itemsDevices.size()) {
            if (mRecvCommunicationListener != null)
                mRecvCommunicationListener.onRecv_B208(itemsDevices);
        } else {
            itemsDevices.clear();
            if (mRecvCommunicationListener != null)
                mRecvCommunicationListener.onRecv_B208Error();
        }
        if (mRecvCommunicationListener != null)
            mRecvCommunicationListener.onRecv_B208(itemsDevices);
    }

    private byte[] getBYZM() {
        try {
            byte[] num = phoneNum.getBytes(ENCODE);
            byte[] buffer = new byte[num.length + 1];
            System.arraycopy(num, 0, buffer, 0, num.length);
            return pkgData(0xA101, buffer);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] getBRegister(boolean isChanged) {
        String str = "";
        if (isChanged)
            str = phoneNum + (char) 0 + userName + (char) 0 + code + (char) 0
                    + (char) 0 + passwordMD5 + (char) 0 + (char) 1;
        else
            str = phoneNum + (char) 0 + userName + (char) 0 + code + (char) 0
                    + (char) 0 + passwordMD5 + (char) 0 + (char) 0;

        try {
            return pkgData(0xA100, str.getBytes(ENCODE));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] getBLoading() {
        byte[] version = int2Bytes(getVersionCode());// word
        String str = phoneNum + (char) 0 + loadIMEI + (char) 0 + (char) 0
                + password + (char) 0 + version[2] + version[3] + (char) 0;
        try {
            return pkgData(0xA103, str.getBytes(ENCODE));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] getBBand(String imei, String plate, String frame,
                            char operation) {
        String str = phoneNum + (char) 0 + imei + (char) 0 + operation + plate
                + (char) 0 + frame + (char) 0;
        try {
            return pkgData(0xA208, str.getBytes(ENCODE));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] getBCarInfo(String imei) {
        String str = phoneNum + (char) 0 + imei + (char) 0;
        try {
            return pkgData(0xA203, str.getBytes(ENCODE));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] getBCarContr(int cmd) {
        byte[] cmdB = int2Bytes(cmd);
        byte[] cmdBytes = new byte[2];
        cmdBytes[0] = cmdB[2];
        cmdBytes[1] = cmdB[3];
        try {
            return pkgData(0xA500, cmdBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private int serialNum = 0;
    private int sendSerialNum = 0;

    public int getsendSerialNum() {
        return sendSerialNum;
    }

    /**
     * 发送数据封装(无分包)
     *
     * @param id   消息ID
     * @param data 消息体
     * @return
     */
    private byte[] pkgData(int id, byte[] data) {
        if (data.length > 1023) {// 长度超出
            return null;
        }
        // 标识位，消息头，消息体，校验位，标识位
        byte[] s = new byte[1 + 12 + data.length + 1 + 1];
        s[0] = (byte) 0x9e;
        s[1] = (byte) (0x00ff & id >> 8);
        s[2] = (byte) (0x00ff & id);
        // 发送命令，属性只有长度
        byte[] attribute = int2Bytes(data.length);
        s[3] = attribute[2];
        s[4] = attribute[3];

        byte[] times = writeDateTimeBCD();
        if (times == null)
            return null;
        System.arraycopy(times, 0, s, 5, times.length);

        if (serialNum > 65535)
            serialNum = 0;
        byte[] cnt = int2Bytes(serialNum);
        sendSerialNum = serialNum;
        s[11] = cnt[2];
        s[12] = cnt[3];
        System.arraycopy(data, 0, s, 13, data.length);
        int jy = getCheckValue(s);
        s[s.length - 2] = int2Bytes(jy)[3];
        s[s.length - 1] = (byte) 0x9e;
        // 转义
        s = escapeCmd(s);
        serialNum++;
        return s;
    }

    private byte[] pkgData(int id, byte data) {

        // 标识位，消息头，消息体，校验位，标识位
        byte[] s = new byte[1 + 12 + 1 + 1 + 1];
        s[0] = (byte) 0x9e;
        s[1] = (byte) (0x00ff & id >> 8);
        s[2] = (byte) (0x00ff & id);
        // 发送命令，属性只有长度
        byte[] attribute = int2Bytes(1);
        s[3] = attribute[2];
        s[4] = attribute[3];

        byte[] times = writeDateTimeBCD();
        if (times == null)
            return null;
        System.arraycopy(times, 0, s, 5, times.length);

        if (serialNum > 65535)
            serialNum = 0;
        byte[] cnt = int2Bytes(serialNum);
        sendSerialNum = serialNum;
        s[11] = cnt[2];
        s[12] = cnt[3];
        s[13] = data;
        int jy = getCheckValue(s);
        s[s.length - 2] = int2Bytes(jy)[3];
        s[s.length - 1] = (byte) 0x9e;
        // 转义
        s = escapeCmd(s);
        serialNum++;
        return s;
    }

    /**
     * 获取检验值
     *
     * @param cmdMsg
     * @return
     */
    private int getCheckValue(byte[] cmdMsg) {
        int jy = 0;
        for (int i = 1; i < cmdMsg.length - 2; i++) {
            jy = jy ^ cmdMsg[i];
        }
        return jy;
    }

    /**
     * 将命令转义
     *
     * @param source
     * @return
     * @see 描述 0x9e<——>0x9d后紧跟一个0x02； 0x9d<——>0x9d后紧跟一个0x01。
     */
    private byte[] escapeCmd(byte[] source) {
        int cnt = source.length;
        // 判断增加几个byte,除去头尾
        for (int i = 1; i < source.length - 1; i++) {
            if (source[i] == (byte) 0x9e || source[i] == (byte) 0x9d)
                cnt++;
        }
        byte[] to = new byte[cnt];
        to[0] = source[0];
        to[to.length - 1] = source[source.length - 1];
        for (int i = 1, j = 1; i < source.length - 1; j++, i++) {
            if (source[i] == (byte) 0x9e) {
                to[j] = (byte) 0x9d;
                to[j + 1] = 0x02;
                j++;
            } else if (source[i] == (byte) 0x9d) {
                to[j] = (byte) 0x9d;
                to[j + 1] = 0x01;
                j++;
            } else {
                to[j] = source[i];
            }
        }

        // String str = "";
        // for (int i = 0; i < to.length; i++) {
        // str += String.format("%02X ", to[i]);
        // }
        // Log.v(TAG, "str : " + str);
        return to;
    }

    /**
     * 将已转义的命令还原
     *
     * @param to
     * @return
     */
    private byte[] reEscapeCmd(byte[] to) {
        int cnt = to.length;
        for (int i = 1; i < to.length - 1; i++) {
            if (to[i] == (byte) 0x9e || to[i] == (byte) 0x9d)
                cnt--;
        }
        byte[] source = new byte[cnt];
        source[0] = (byte) 0x9e;
        source[source.length - 1] = (byte) 0x9e;
        for (int i = 1, j = 1; i < source.length - 1; j++, i++) {
            if (to[j] == (byte) 0x9d && to[j + 1] == (byte) 0x01) {
                source[i] = (byte) 0x9d;
                j++;
            } else if (to[j] == (byte) 0x9d && to[j + 1] == (byte) 0x02) {
                source[i] = (byte) 0x9e;
                j++;
            } else {
                source[i] = to[j];
            }
        }
        // String str = "";
        // for (int i = 0; i < source.length; i++) {
        // str += String.format("%02X ", source[i]);
        // }
        // Log.v(TAG, "str : " + str);
        return source;
    }

    /**
     * 当前时间 十进制显示到命令中
     *
     * @return
     */
    private byte[] writeDateTimeBCD() {
        String date = sdf.format(new java.util.Date());
        byte[] dbuffer;
        try {
            dbuffer = date.getBytes("UTF-8");
            byte[] tbuffer = new byte[6];

            for (int i = 0; i < 6; i++) {
                tbuffer[i] = (byte) (((dbuffer[i * 2] - 0x30) * 16) + (dbuffer[i * 2 + 1] - 0x30));
            }
            return tbuffer;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 读取命令中的字符串 byte长度
     *
     * @param message
     * @param offset
     * @return
     */
    private int getCmdStringLength(byte[] message, int offset) {
        int length = 0;
        for (int i = offset; i < message.length; i++) {
            if (message[i] == 0) {
                length = i - offset;
                break;
            }
        }
        return length;
    }

    /**
     * 读取命令中的字符串
     *
     * @param message
     * @param offset
     * @return
     */
    public static String getCmdString(byte[] message, int offset) {
        int length = 0;
        for (int i = offset; i < message.length; i++) {
            if (message[i] == (byte) 0x0) {
                length = i - offset;
                break;
            }
        }
        String describeStr = "";
        if (length > 0) {
            byte[] describe = new byte[length];
            System.arraycopy(message, offset, describe, 0, length);
            try {
                describeStr = new String(describe, ENCODE);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return describeStr;
    }

    /**
     * 获取版本号(内部识别号)
     *
     * @param context
     * @return
     */
    private int getVersionCode() {
        try {
            PackageInfo pi = mContext.getPackageManager().getPackageInfo(
                    mContext.getPackageName(), 0);
            return pi.versionCode;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    public static byte[] str2Bytes(String str) {
        try {
            return str.getBytes(ENCODE);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getMD5(String val) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(val.getBytes());
        byte[] b = md5.digest();// 加密
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            sb.append(b[i]);
        }
        return sb.toString();
    }

    /*----------------------------------------------------*/
    public static byte[] int2Bytes(int num) {
        byte[] byteNum = new byte[4];
        for (int ix = 0; ix < 4; ++ix) {
            int offset = 32 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    public static int bytes2Int(byte[] byteNum) {
        int num = 0;
        for (int ix = 0; ix < 4; ++ix) {
            num <<= 8;
            num |= (byteNum[ix] & 0xff);
        }
        return num;
    }

    public static byte[] long2Bytes(long num) {
        byte[] byteNum = new byte[8];
        for (int ix = 0; ix < 8; ++ix) {
            int offset = 64 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    public static long bytes2Long(byte[] byteNum) {
        long num = 0;
        for (int ix = 0; ix < 8; ++ix) {
            num <<= 8;
            num |= (byteNum[ix] & 0xff);
        }
        return num;
    }

    /**
     * 十六进制 以10进制显示 取值
     *
     * @return e.g: 0x20 ---> 20
     */
    public static int byte2Int(byte data) {
        return (data / 16 + data % 16);
    }

    private int getCmdLength(byte h, byte l) {
        int length = l & 0xff;
        int l8 = getBooleanArray(h)[7];
        if (l8 == 1)
            length += 256;
        int l9 = getBooleanArray(h)[6];
        if (l9 == 1)
            length += 512;
        return length;
    }

    /**
     * 将byte转换为一个长度为8的byte数组，数组每个值代表bit
     */
    public static byte[] getBooleanArray(byte b) {
        byte[] array = new byte[8];
        for (int i = 7; i >= 0; i--) {
            array[i] = (byte) (b & 1);
            b = (byte) (b >> 1);
        }
        return array;
    }

    public static int G_BIT(byte[] msg, int byteIndex, int bitIndex, int count) {
        int b = G_BYTE(msg, byteIndex);
        int mask = 0;
        for (int i = 0; i < count; i++) {
            int bb = 1 << i;
            mask |= bb;
        }
        return b >> bitIndex & mask;
    }

    /**
     * @param msg
     * @param i   是低位
     * @return
     */
    public static int G_WORD(byte[] msg, int i) {
        int ret = (msg[i + 1] & 0xFF) * 0x100 + (msg[i] & 0xFF);
        return ret;
    }

    /**
     * @param msg
     * @param i   是高位
     * @return
     */
    public static int G_WORD_H(byte[] msg, int i) {
        int ret = (msg[i] & 0xFF) * 0x100 + (msg[i + 1] & 0xFF);
        return ret;
    }

    /**
     * 获取msg中的i的值
     */
    public static int G_BYTE(byte[] msg, int i) {
        return msg[i] & 0xFF;
    }

    private void printfByte(String log, String tag, byte[] bits) {
        String str = "";
        for (int i = 0; i < bits.length; i++) {
            str += String.format("%02X ", bits[i]);
        }
        if (log.equals("i"))
            Log.i(TAG, tag + ": " + str);
        else if (log.equals("d"))
            Log.d(TAG, tag + ": " + str);
        else if (log.equals("e"))
            Log.e(TAG, tag + ": " + str);
        else
            Log.v(TAG, tag + ": " + str);
    }

}
